package main

import (
	"fmt"
	"html/template"
	"math/rand"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

const (
	lowercaseLetters = "abcdefghijklmnopqrstuvwxyz"
	uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	digits           = "0123456789"
	specialChars     = "!@#$%^&*()_+{}[]|\\:;'<>,.?/~`"
)

func main() {
	rand.New(rand.NewSource(time.Now().Unix()))

	http.HandleFunc("/", handleIndex)
	http.HandleFunc("/generate", handleGenerate)
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))

	fmt.Println("Server started at http://localhost:8080")
	http.ListenAndServe(":8080", nil)
}

func handleIndex(w http.ResponseWriter, r *http.Request) {
	tmpl, err := template.ParseFiles("./templates/index.html")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	tmpl.Execute(w, nil)
}

func handleGenerate(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	r.ParseForm()
	minLength := r.FormValue("minLength")
	maxLength := r.FormValue("maxLength")
	charset := r.FormValue("charset")
	count := r.FormValue("count")

	// Generate passwords
	passwords := generatePasswords(minLength, maxLength, charset, count)

	// Save to file
	filename := "./static/results.txt"
	err := os.WriteFile(filename, []byte(strings.Join(passwords, "\n")), 0644)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Render passwords on the page
	tmpl, err := template.ParseFiles("./templates/index.html")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	data := struct {
		Passwords []string
		Filename  string
	}{
		Passwords: passwords,
		Filename:  filepath.Base(filename),
	}
	tmpl.Execute(w, data)
}

func generatePasswords(minLength, maxLength, charset, count string) []string {
	minLen, err := strconv.Atoi(minLength)
	if err != nil {
		minLen = 1
	}
	maxLen, err := strconv.Atoi(maxLength)
	if err != nil {
		maxLen = 8
	}
	numPasswords, err := strconv.Atoi(count)
	if err != nil {
		numPasswords = 10
	}

	var charPool string
	if strings.Contains(charset, "lowercase") {
		charPool += lowercaseLetters
	}
	if strings.Contains(charset, "uppercase") {
		charPool += uppercaseLetters
	}
	if strings.Contains(charset, "digits") {
		charPool += digits
	}
	if strings.Contains(charset, "special") {
		charPool += specialChars
	}

	if charPool == "" {
		charPool = lowercaseLetters + uppercaseLetters + digits + specialChars
	}

	passwords := make([]string, numPasswords)
	for i := 0; i < numPasswords; i++ {
		length := rand.Intn(maxLen-minLen+1) + minLen
		password := make([]byte, length)
		for j := 0; j < length; j++ {
			password[j] = charPool[rand.Intn(len(charPool))]
		}
		passwords[i] = string(password)
	}
	return passwords
}
